package com.xiaoa.gossip.cluster.service.impl;

import com.xiaoa.gossip.cluster.command.PingCommand;
import com.xiaoa.gossip.cluster.command.PingNodeState;
import com.xiaoa.gossip.cluster.event.NoteConnectFailEvent;
import com.xiaoa.gossip.cluster.service.ClusterClientService;
import com.xiaoa.gossip.cluster.service.ClusterService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.util.List;

import static com.xiaoa.gossip.cluster.constant.ClusterMethodConstant.PING_METHOD_NAME;

/**
 * 客户端请求服务
 *
 * @author luokaichuang
 * @time 2020/5/9
 */
@Service
public class ClusterClientServiceImpl implements ClusterClientService {


    @Qualifier("pingRestTemplate")
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ClusterService clusterService;

    @Autowired
    private ApplicationContext applicationContext;

    private static final Logger LOGGER = LoggerFactory.getLogger(ClusterClientServiceImpl.class);

    @Override
    public void doBroadcast(String method, List<PingNodeState> pingNodeStateList, PingCommand pingCommand) {

        LOGGER.debug("=================== 广播开始");

        pingNodeStateList.forEach(s -> doRequest(s, pingCommand, method));

        LOGGER.debug("=================== 广播完毕");

    }


    /*
     *  向客户端发送请求
     * @author jm008783
     * @param: [nodeState, pingCommand]
     * @return: void
     **/
    private void doRequest(PingNodeState nodeState, PingCommand pingCommand, String method) {

        try {
            String url = "http://" + nodeState.getIp() + ":" + nodeState.getPort() + "/cluster/" + method;
            PingCommand pongCommand = restTemplate.postForObject(url, pingCommand, PingCommand.class);

            // 如果是ping
            if (method.equals(PING_METHOD_NAME)) {
                clusterService.updatePingLastTime(nodeState.getId());
            }

            if (pongCommand != null) {
                // 处理数据
                clusterService.doPongHandle(pongCommand);
            }


        } catch (RestClientException re) {
            pushFailEvent(nodeState, method);
            LOGGER.warn("======= 连接失败 ：{}{}", (nodeState.getIp() + ":" + nodeState.getPort()), re);

        } catch (Exception e) {
            LOGGER.error("处理Pong异常:{}", e);
        }


    }


    /**
     * 向客户端发送请求失败事件
     *
     * @author jm008783
     * @param: [pingCommand]
     * @return: void
     **/
    private void pushFailEvent(PingNodeState pingCommand, String method) {
        // 请求失败，发送请求失败事件
        applicationContext.publishEvent(new NoteConnectFailEvent(pingCommand, method));
    }


}
